#include <stdafx.h>
#include <cassert>
#include <sstream>
#include "global.h"

AdderBytecodeEngine * engine_state;
std::vector<unsigned int> * function_registration_argument_names;

// Engine
void engine_init(unsigned int variable_size, unsigned int register_size)
{
	assert(engine_state == NULL);

	_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
	//_CrtSetBreakAlloc(352);
	//_CrtSetBreakAlloc(355);
	//_CrtSetBreakAlloc(373);
	
	if (function_registration_argument_names == NULL)
		function_registration_argument_names = new std::vector<unsigned int>();

	engine_state = new AdderBytecodeEngine(variable_size, register_size);
}

void debug_on()
{
	assert(engine_state != NULL);

	engine_state->debug = true;

	printf("[Adder NE] Debugging has been enabled!\n");
}

void engine_cleanup()
{
	assert(engine_state != NULL);

	delete engine_state;
	delete function_registration_argument_names;

#ifdef STRING_ALLOC_DEBUG
	printf("STRINGS LEFT: %i		VALUES LEFT: %i\n", stringsAllocated, valuesAllocated);
#endif
}

void engine_builtin_load_library(BuiltinInitalizer func)
{
	assert(engine_state != NULL);

	engine_state->BuiltinLoadLibrary(func);
}

void engine_register_function_argument(unsigned int function_argument)
{
	assert(engine_state != NULL);

	function_registration_argument_names->insert(function_registration_argument_names->end(), function_argument);
}

void engine_register_function_call(const char* function_name)
{
	assert(engine_state != NULL);

	// Now actually register the function
	engine_state->UserRegisterFunction(function_name, *function_registration_argument_names);
	function_registration_argument_names->clear();
}

void engine_register_function_class_call(const char* function_name, const char* class_name, void * jmp_location)
{
	assert(engine_state != NULL);

	// Now actually register the function
	engine_state->UserRegisterClassFunction(function_name, class_name, jmp_location, *function_registration_argument_names);
	function_registration_argument_names->clear();
}

void engine_register_class(const char* class_name)
{
	assert(engine_state != NULL);

	// Register class here...
}

bool engine_get_assembly_jump_required()
{
	assert(engine_state != NULL);

	bool a = engine_state->assembly_jump_required;
	engine_state->assembly_jump_required = false;
	return a;
}

void * engine_get_assembly_class_jump_position()
{
	assert(engine_state != NULL);

	void * a = engine_state->assembly_jump_class_position;
	engine_state->assembly_jump_class_position = NULL;
	return a;
}

bool engine_get_is_breaking()
{
	assert(engine_state != NULL);

	return engine_state->breaking;
}

void engine_scope_cleanup()
{
	assert(engine_state != NULL);

	engine_state->ScopeCleanup();
}

// Bytecode: Register Creation
void do_NEWC	(int reg, const char* cls)
{
	assert(engine_state != NULL);

	engine_state->NEWC(reg, cls);
}

void do_NEWA	(int reg)
{
	assert(engine_state != NULL);

	engine_state->NEWA(reg);
}

void do_NEWS	(int reg, const char* str)
{
	assert(engine_state != NULL);

	engine_state->NEWS(reg, str);
}

void do_NEWN	(int reg, float number)
{
	assert(engine_state != NULL);

	engine_state->NEWN(reg, number);
}

// Bytecode: Register / Variable Movement and Basic Comparisons
void do_RMOVV	(int reg, int var)
{
	assert(engine_state != NULL);

	engine_state->RMOVV(reg, var);
}

void do_RMOVA	(int reg, int var, float index)
{
	assert(engine_state != NULL);

	engine_state->RMOVA(reg, var, index);
}

void do_RMOVP	(int reg, const char* prop, int object)
{
	assert(engine_state != NULL);

	engine_state->RMOVP(reg, prop, object);
}

void do_MOVV	(int reg, int var)
{
	assert(engine_state != NULL);

	engine_state->MOVV(reg, var);
}

void do_MOVA	(int reg, int var, float index)
{
	assert(engine_state != NULL);

	engine_state->MOVA(reg, var, index);
}

void do_MOVP	(int reg, const char* prop, int object)
{
	assert(engine_state != NULL);

	engine_state->MOVP(reg, prop, object);
}

void do_DMOVV	(int reg, int reg2)
{
	assert(engine_state != NULL);

	engine_state->DMOVV(reg, reg2);
}

void do_DMOVA	(int reg, int reg2, float index)
{
	assert(engine_state != NULL);

	engine_state->DMOVA(reg, reg2, index);
}

void do_DDMOVA	(int reg, int reg2, int reg3)
{
	assert(engine_state != NULL);

	engine_state->DDMOVA(reg, reg2, reg3);
}

void do_DRMOVA	(int reg, int reg2, float index)
{
	assert(engine_state != NULL);

	engine_state->DRMOVA(reg, reg2, index);
}

void do_DRMOVP	(int reg, const char* prop, int reg2)
{
	assert(engine_state != NULL);

	engine_state->DRMOVP(reg, prop, reg2);
}

void do_DDRMOVA	(int reg, int reg2, int reg3)
{
	assert(engine_state != NULL);

	engine_state->DDRMOVA(reg, reg2, reg3);
}

void do_REFA	(int reg, int var, float index)
{
	assert(engine_state != NULL);

	engine_state->REFA(reg, var, index);
}

void do_REFP	(int reg, const char* prop, int object)
{
	assert(engine_state != NULL);

	engine_state->REFP(reg, prop, object);
}

void do_CMPV	(int res, int reg, const char* str)
{
	assert(engine_state != NULL);

	engine_state->CMPV(res, reg, str);
}

void do_CMPV	(int res, int reg, float number)
{
	assert(engine_state != NULL);

	engine_state->CMPV(res, reg, number);
}

void do_CMPR	(int res, int reg, int reg2)
{
	assert(engine_state != NULL);

	engine_state->CMPR(reg, reg, reg2);
}

// Bytecode: Breaks
void do_BVS		(const char* label, int var)
{
	assert(engine_state != NULL);

	engine_state->BVS(label, var);
}

void do_BVNS	(const char* label, int var)
{
	assert(engine_state != NULL);

	engine_state->BVNS(label, var);
}

void do_BRS		(const char* label, int reg)
{
	assert(engine_state != NULL);

	engine_state->BRS(label, reg);
}

void do_BRNS	(const char* label, int reg)
{
	assert(engine_state != NULL);

	engine_state->BRNS(label, reg);
}

void do_BT		(const char* label, int reg)
{
	assert(engine_state != NULL);

	engine_state->BT(label, reg);
}

void do_BF		(const char* label, int reg)
{
	assert(engine_state != NULL);

	engine_state->BF(label, reg);
}

void do_BU		(const char* label)
{
	assert(engine_state != NULL);

	engine_state->BU(label);
}

void do_BERR	(const char* label, int reg,  int reg2)
{
	assert(engine_state != NULL);

	engine_state->BERR(label, reg, reg2);
}

void do_BRK		(const char* label)
{
	assert(engine_state != NULL);

	engine_state->BRK(label);
}

// Bytecode: Register / Variable Cleanup
void do_CLR		(int reg)
{
	assert(engine_state != NULL);

	engine_state->CLR(reg);
}

void do_CLRV	(int var)
{
	assert(engine_state != NULL);

	engine_state->CLRV(var);
}

// Bytecode: Labels / Jumps
void do_LBL		(const char* label)
{
	assert(engine_state != NULL);

	engine_state->LBL(label);
}

void do_JMPR	(float position)
{
	assert(engine_state != NULL);

	engine_state->JMPR(position);
}

void do_JMPA	(float position)
{
	assert(engine_state != NULL);

	engine_state->JMPA(position);
}

void do_JMPL	(const char* label)
{
	assert(engine_state != NULL);

	engine_state->JMPL(label);
}

// Bytecode: Return System
void do_RET		(int reg)
{
	assert(engine_state != NULL);

	engine_state->RET(reg);
}

// Bytecode: Arithmetic Functions
void do_ADD		(int reg, const char* str)
{
	assert(engine_state != NULL);

	engine_state->ADD(reg, str);
}

void do_ADD		(int reg, int reg2)
{
	assert(engine_state != NULL);

	engine_state->ADD(reg, reg2);
}

void do_ADD		(int reg, float value)
{
	assert(engine_state != NULL);

	engine_state->ADD(reg, value);
}

void do_SUB		(int reg, int reg2)
{
	assert(engine_state != NULL);

	engine_state->SUB(reg, reg2);
}

void do_SUB		(int reg, float value)
{
	assert(engine_state != NULL);

	engine_state->SUB(reg, value);
}

void do_MUL		(int reg, int reg2)
{
	assert(engine_state != NULL);

	engine_state->MUL(reg, reg2);
}

void do_MUL		(int reg, float value)
{
	assert(engine_state != NULL);

	engine_state->MUL(reg, value);
}

void do_DIV		(int reg, int reg2)
{
	assert(engine_state != NULL);

	engine_state->DIV(reg, reg2);
}

void do_DIV		(int reg, float value)
{
	assert(engine_state != NULL);

	engine_state->DIV(reg, value);
}

void do_POW		(int reg, int reg2)
{
	assert(engine_state != NULL);

	engine_state->POW(reg, reg2);
}

void do_POW		(int reg, float value)
{
	assert(engine_state != NULL);

	engine_state->POW(reg, value);
}

// Bytecode: Arithmetic Comparisons
void do_EQ		(int reg, int reg2)
{
	assert(engine_state != NULL);

	engine_state->EQ(reg, reg2);
}

void do_NE		(int reg, int reg2)
{
	assert(engine_state != NULL);

	engine_state->NE(reg, reg2);
}

void do_LT		(int reg, int reg2)
{
	assert(engine_state != NULL);

	engine_state->LT(reg, reg2);
}

void do_LE		(int reg, int reg2)
{
	assert(engine_state != NULL);

	engine_state->LE(reg, reg2);
}

void do_GT		(int reg, int reg2)
{
	assert(engine_state != NULL);

	engine_state->GT(reg, reg2);
}

void do_GE		(int reg, int reg2)
{
	assert(engine_state != NULL);

	engine_state->GE(reg, reg2);
}

// Bytecode: Function Calling
void do_CALLF	(const char* func, int arglist, int ret)
{
	assert(engine_state != NULL);

	engine_state->CALLF(func, arglist, ret);
}

void do_CALLC	(const char* func, int arglist, int ret, int object)
{
	assert(engine_state != NULL);

	engine_state->CALLC(func, arglist, ret, object);
}

// Bytecode: Errors
void do_ERR		(float position, const char* msg)
{
	assert(engine_state != NULL);

	engine_state->ERR(position, msg);
}